#pragma once
#include <iostream>
#include <fstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include "Log.hpp"
#include "Thread.hpp"
#define BUFFER_SIZE 1024
#define DEFAULT_PROT 8888

using namespace LogModule;
const std::string login = "login";
const std::string logout = "logout";
const std::string route = "route";
const std::string esp = ": ";
const std::string chat_file = "./ChatGroup.txt";

class UDPClient
{
public:
    UDPClient(const std::string &ip, in_port_t port)
        : _server_addr_len(sizeof(_server_addr))
        , _sender("sender", [this](){Send();})
        , _reciver("reciver", [this](){Recive();})
    {
        _server_addr.sin_addr.s_addr = inet_addr(ip.c_str());
        _server_addr.sin_family = AF_INET;
        _server_addr.sin_port = htons(port);

        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket: 套接字创建失败! ";
            exit(errno);
        }
        LOG(LogLevel::INFO) << "UDPClient: UDP套接字(sockfd=" << _sockfd << ")创建成功";
    }
    ~UDPClient()
    {
        _sender.Join();
        _reciver.Join();
        close(_sockfd);
    }
    UDPClient(const UDPClient&) = delete;
    UDPClient& operator=(const UDPClient&) = delete;
    void Start()
    {
        _sender.Start();
    }
    void Send()
    {
        std::string name, info;
        char buffer[BUFFER_SIZE] = {0};
        do
        {
            std::cout << "输入用户名以加入聊天: ";
            std::getline(std::cin, name);
            info = "login: " + name;
            sendto(_sockfd, info.c_str(), info.size(), 0, (struct sockaddr*)&_server_addr, _server_addr_len);
            ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&_server_addr, &_server_addr_len);
            buffer[n] = 0;
            std::cout << buffer << std::endl;
        } while(buffer != login);
        _reciver.Start();
        do
        {
            std::cout << "发送到公屏: ";
            std::getline(std::cin, info);
            if(info == logout)
                info += esp;
            else
                info = route + esp + info;
            sendto(_sockfd, info.c_str(), info.size(), 0, (struct sockaddr*)&_server_addr, _server_addr_len);
        }while(info != logout + esp);
    }
    void Recive()
    {
        std::fstream clean(chat_file, std::ios::out);
        clean.close();
        std::fstream ChatGroup("./ChatGroup.txt", std::ios::app);
        char buffer[BUFFER_SIZE];
        do
        {
            ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&_server_addr, &_server_addr_len);
            buffer[n] = 0;
            ChatGroup << buffer << std::endl;
            fflush(stdout);
        }while(buffer != logout);
        ChatGroup.close();
    }

private:
    int _sockfd;
    struct sockaddr_in _server_addr;
    socklen_t _server_addr_len;
    ThreadModule::Thread _sender;
    ThreadModule::Thread _reciver;
};